#include "stdafx.h"
#include "InputDevice.h"

//////////////////////////////////////////////////////////////////////////

KeyboardDevice::KeyboardDevice(EventChannel* channel)
{
	m_InputChannel = channel;
	m_Keyboard = g_App->GetAppListener()->GetKeyboard();
	m_IsRepeat = false;
	m_IsCapslock = false;

#ifdef WIN32
	if (GetKeyState(VK_CAPITAL))
		m_IsCapslock = true;
#endif
}

KeyboardDevice::~KeyboardDevice()
{
}

void KeyboardDevice::UpdateKeyboard(float dt)
{
	KeyBit oldbit = m_Pressed;

	if (!ReadRawInput(dt))
		return;

	m_Triggered = m_Pressed & (m_Pressed ^ oldbit);
	m_Released	= oldbit	& (m_Pressed ^ oldbit);

	if (oldbit != m_Pressed)
	{
		m_Repeated.clear();
		m_RepeatTimer = 0.3f;
	}

	if (m_RepeatTimer > 0.0f)
	{
		m_RepeatTimer -= dt;

		if (m_RepeatTimer <= 0.0f)
		{
			m_Repeated = m_Pressed;
			m_RepeatTimer = 0.25f;
			m_IsRepeat = true;
		}
	}
	else
	{
		m_Repeated.clear();
	}
	
	// TODO : process run before capital state is don't know
	if (IsTriggered(OIS::KC_CAPITAL))
		m_IsCapslock = !m_IsCapslock;

	if (m_Triggered.isEmpty() || m_Released.isEmpty() || m_Repeated.isEmpty())
	{
		g_InputService->GetInputChannel()->Broadcast(&InputKeyEvent());
		m_IsRepeat = false;
	}
}

bool KeyboardDevice::ReadRawInput(float dt)
{
	m_Pressed.clear();

	for (uint i = 1; i <= (uint)OIS::KC_MEDIASELECT; ++i)
	{
		m_Pressed.set(i, m_Keyboard->isKeyDown((OIS::KeyCode)i));
	}
	
	m_Modifier.set(OIS::Keyboard::Shift, m_Keyboard->isModifierDown(OIS::Keyboard::Shift));
	m_Modifier.set(OIS::Keyboard::Ctrl, m_Keyboard->isModifierDown(OIS::Keyboard::Ctrl));
	m_Modifier.set(OIS::Keyboard::Alt, m_Keyboard->isModifierDown(OIS::Keyboard::Alt));
	
	return true;
}

bool KeyboardDevice::IsPressed(OIS::KeyCode code)
{
	return m_Pressed.contains((u32)code);
}

bool KeyboardDevice::IsReleased(OIS::KeyCode code)
{
	return m_Released.contains((u32)code);
}

bool KeyboardDevice::IsTriggered(OIS::KeyCode code)
{
	return m_Triggered.contains((u32)code);
}

bool KeyboardDevice::IsRepeated(OIS::KeyCode code)
{
	return m_IsRepeat && m_Repeated.contains((u32)code);
}

bool KeyboardDevice::IsModifier(OIS::Keyboard::Modifier modifier)
{
	return m_Modifier.any(modifier);
}
//////////////////////////////////////////////////////////////////////////

MouseDevice::MouseDevice(EventChannel* channel)
{
	m_InputChannel = channel;
	m_Mouse	= g_App->GetAppListener()->GetMouse();
	m_IsRepeat = false;
}

MouseDevice::~MouseDevice()
{
}

void MouseDevice::UpdateMouse(float dt)
{
	// Send MouseEvent
	BitSet oldbit = m_Pressed;
	OIS::MouseState state = m_Mouse->getMouseState();

	if (!ReadRawInput(dt, state))
		return;

	m_Triggered	= m_Pressed & (m_Pressed ^ oldbit);
	m_Released	= oldbit	& (m_Pressed ^ oldbit);

	if (oldbit != m_Pressed)
	{
		m_Repeated.clear();
		m_RepeatTimer = 0.3;
	}

	if (m_RepeatTimer > 0.0f)
	{
		m_RepeatTimer -= dt;

		if (m_RepeatTimer <= 0.0f)
		{
			m_Repeated = m_Pressed;
			m_RepeatTimer = 0.25f;
			m_IsRepeat = true;
		}
	}
	else
	{
		m_Repeated.clear();
	}

	if ((m_Triggered || m_Released || m_Repeated) ||
		(state.X.rel != 0 || state.Y.rel != 0 || state.Z.rel != 0))
	{
		g_InputService->GetInputChannel()->Broadcast(&InputMouseEvent(state.X, state.Y, state.Z));
		m_IsRepeat = false;
	}
}

bool MouseDevice::ReadRawInput(float dt, OIS::MouseState& state)
{
	m_Pressed.clear();

	for (int i = 0; i <= (int)OIS::MB_Middle; ++i)
	{
		m_Pressed.set(
			ConvertBitValue((OIS::MouseButtonID)i), 
							state.buttonDown((OIS::MouseButtonID)i));
	}

	return true;
}

bool MouseDevice::IsPressed( OIS::MouseButtonID code )
{
	return m_Pressed.any(ConvertBitValue(code));
}

bool MouseDevice::IsReleased( OIS::MouseButtonID code )
{
	return m_Released.any(ConvertBitValue(code));
}

bool MouseDevice::IsTriggered( OIS::MouseButtonID code )
{
	return m_Triggered.any(ConvertBitValue(code));
}

bool MouseDevice::IsRepeated( OIS::MouseButtonID code )
{
	return m_Repeated.any(ConvertBitValue(code));
}

MouseDevice::Buttons MouseDevice::ConvertBitValue(OIS::MouseButtonID code)
{
	Buttons btn;
	switch(code)
	{
	case OIS::MB_Left:		btn = MOUSE_LEFT; break;
	case OIS::MB_Right:		btn = MOUSE_RIGHT; break;
	case OIS::MB_Middle:	btn = MOUSE_MIDDLE; break;
	}

	return btn;
}

//////////////////////////////////////////////////////////////////////////

IMPLEMENT_EVENT(InputKeyEvent);

bool InputKeyEvent::IsPressed(OIS::KeyCode code)
{
	return g_InputService->KeyIsPressed(code);
}

bool InputKeyEvent::IsReleased(OIS::KeyCode code)
{
	return g_InputService->KeyIsReleased(code);
}

bool InputKeyEvent::IsTriggered(OIS::KeyCode code)
{
	return g_InputService->KeyIsTriggered(code);
}

bool InputKeyEvent::IsRepeated(OIS::KeyCode code)
{
	return g_InputService->KeyIsRepeated(code);
}

bool InputKeyEvent::IsModifier( OIS::Keyboard::Modifier modifier )
{
	return g_InputService->KeyIsModifier(modifier);
}

bool InputKeyEvent::IsCapsLock()
{
	return g_InputService->KeyIsCapsLock();
}
//////////////////////////////////////////////////////////////////////////

IMPLEMENT_EVENT(InputMouseEvent);

bool InputMouseEvent::IsPressed(OIS::MouseButtonID code)
{
	return g_InputService->MouseIsPressed(code);
}

bool InputMouseEvent::IsReleased(OIS::MouseButtonID code)
{
	return g_InputService->MouseIsReleased(code);
}

bool InputMouseEvent::IsTriggered(OIS::MouseButtonID code)
{
	return g_InputService->MouseIsTriggered(code);
}

bool InputMouseEvent::IsRepeated(OIS::MouseButtonID code)
{
	return g_InputService->MouseIsRepeated(code);
}